
<html>

	<head>
		<title>Learning WebGL &mdash; lesson 4</title>
		<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

		<script type="text/javascript" src="sylvester.js"></script>
		<script type="text/javascript" src="glUtils.js"></script>

		<script id="shader-fs" type="x-shader/x-fragment">
			#ifdef GL_ES
			precision highp float;
			#endif
			
			varying float vColor;

			void main(void) {
				gl_FragColor = vec4(vColor, vColor, vColor, 1.0);
			}
		</script>

		<script id="shader-vs" type="x-shader/x-vertex">
			attribute vec2 aVertexPosition;
			attribute float aVertexPosition1;

			uniform mat4 uMVMatrix;
			uniform mat4 uPMatrix;
			
			varying float vColor;

			void main(void) {
				gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition.x, aVertexPosition1, aVertexPosition.y, 1.0);
				vColor = aVertexPosition1 * 0.5;
			}
		</script>


		<script type="text/javascript">

			var gl;
			function initGL(canvas) {
				try {
					gl = canvas.getContext("experimental-webgl");
					gl.viewportWidth = canvas.width;
					gl.viewportHeight = canvas.height;
				} catch(e) {
				}
				if (!gl) {
					alert("Could not initialise WebGL, sorry :-(");
				}
			}


			function getShader(gl, id) {
				var shaderScript = document.getElementById(id);
				if (!shaderScript) {
					return null;
				}

				var str = "";
				var k = shaderScript.firstChild;
				while (k) {
					if (k.nodeType == 3) {
						str += k.textContent;
					}
					k = k.nextSibling;
				}

				var shader;
				if (shaderScript.type == "x-shader/x-fragment") {
					shader = gl.createShader(gl.FRAGMENT_SHADER);
				} else if (shaderScript.type == "x-shader/x-vertex") {
					shader = gl.createShader(gl.VERTEX_SHADER);
				} else {
					return null;
				}

				gl.shaderSource(shader, str);
				gl.compileShader(shader);

				if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
					alert(gl.getShaderInfoLog(shader));
					return null;
				}

				return shader;
			}


			var shaderProgram;
			function initShaders() {
				var fragmentShader = getShader(gl, "shader-fs");
				var vertexShader = getShader(gl, "shader-vs");

				shaderProgram = gl.createProgram();
				gl.attachShader(shaderProgram, vertexShader);
				gl.attachShader(shaderProgram, fragmentShader);
				gl.linkProgram(shaderProgram);

				if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
					alert("Could not initialise shaders");
				}

				gl.useProgram(shaderProgram);

				shaderProgram.vertexYAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition1");
				gl.enableVertexAttribArray(shaderProgram.vertexYAttribute);

				shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
				gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

				shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
				shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
			}


			var mvMatrix;
			var mvMatrixStack = [];

			function mvPushMatrix(m) {
				if (m) {
					mvMatrixStack.push(m.dup());
					mvMatrix = m.dup();
				} else {
					mvMatrixStack.push(mvMatrix.dup());
				}
			}

			function mvPopMatrix() {
				if (mvMatrixStack.length == 0) {
					throw "Invalid popMatrix!";
				}
				mvMatrix = mvMatrixStack.pop();
				return mvMatrix;
			}

			function loadIdentity() {
				mvMatrix = Matrix.I(4);
			}


			function multMatrix(m) {
				mvMatrix = mvMatrix.x(m);
			}

			function mvTranslate(v) {
				var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4();
				multMatrix(m);
			}

			function mvRotate(ang, v) {
				var arad = ang * Math.PI / 180.0;
				var m = Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
				multMatrix(m);
			}

			var pMatrix;
			function perspective(fovy, aspect, znear, zfar) {
				pMatrix = makePerspective(fovy, aspect, znear, zfar);
			}


			function setMatrixUniforms() {
				gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
				gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
			}


			var squareVertexPositionBuffer;
			var squareVertexYBuffer;
			var squareVertexIndexBuffer;
			function initBuffers() {

//				vertices = new Float32Array([
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2,
//				Math.random() * 2
//				
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0,
////				Math.random() * 0
//				]);
//				squareVertexYBuffer = gl.createBuffer();
//				gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexYBuffer);
//				gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

				var vertices = new Float32Array([
				-5,-5,Math.random() * 2,0,
				0,-5,Math.random() * 2,0,
				5,-5,Math.random() * 2,0,
				-5,0,Math.random() * 2,0,
				0,0,Math.random() * 2,0,
				5,0,Math.random() * 2,0,
				-5,5,Math.random() * 2,0,
				0,5,Math.random() * 2,0,
				5,5,Math.random() * 2,0,
				
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2,
				Math.random() * 2
				]);
				squareVertexPositionBuffer = gl.createBuffer();
				gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
				gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

				var indices = new Uint16Array([
					0,3,1,4,2,5,5,3,3,6,4,7,5,8
				]);
				squareVertexIndexBuffer = gl.createBuffer();
				gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareVertexIndexBuffer);
				gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
			}


			var rPyramid = 0;
			var rCube = 0;
			function drawScene() {
				gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
				gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
				gl.enable( gl.CULL_FACE );
				gl.cullFace( gl.BACK );

				perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
				loadIdentity();

				mvTranslate([0.0, -4.0, -20.0])

				mvPushMatrix();
				mvRotate(rCube, [0, 1, 0]);
				setMatrixUniforms();

				gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);

//				gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
				gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 4*4, 0);
				gl.vertexAttribPointer(shaderProgram.vertexYAttribute, 1, gl.FLOAT, false, 4, 36*4);

				gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareVertexIndexBuffer);
				gl.drawElements(gl.TRIANGLE_STRIP, 14, gl.UNSIGNED_SHORT, 0);

				mvPopMatrix();

			}


			var lastTime = 0;
			function animate() {
				var timeNow = new Date().getTime();
				if (lastTime != 0) {
					var elapsed = timeNow - lastTime;

					rPyramid += (90 * elapsed) / 1000.0;
					rCube -= (75 * elapsed) / 1000.0;
				}
				lastTime = timeNow;
			}


			function tick() {
				drawScene();
				animate();
			}


			function webGLStart() {
				var canvas = document.getElementById("lesson04-canvas");
				initGL(canvas);
				initShaders()
				initBuffers();

				gl.clearColor(0.0, 0.0, 0.0, 1.0);

				gl.clearDepth(1.0);

				gl.enable(gl.DEPTH_TEST);
				gl.depthFunc(gl.LEQUAL);

				setInterval(tick, 15);
			}


		</script>


	</head>


	<body onload="webGLStart();">
		<canvas id="lesson04-canvas" style="border: none;" width="500" height="500"></canvas>


	</body>

</html>